#include "FileAnalysis.h"

#include <string.h>
#include <iostream>
#include <QString>
#include <string>

void MusicFileInfo::printInfo()
{
    if(Name.size() > 0)
    {
        qDebug() << "歌曲：" << Name;
    }
    else
    {
        qDebug() << "歌曲：暂无";
    }

    if(Album.size() > 0)
    {
        qDebug() << "专辑：" << Album;
    }
    else
    {
        qDebug() << "专辑：暂无";
    }

    if(Singer.size() > 0)
    {
        qDebug() << "歌手：" << Singer;
    }
    else
    {
        qDebug() << "歌手：暂无";
    }

    if(pic_flag)
    {
        qDebug() << "封面：有";
    }
    else
    {
        qDebug() << "封面：无";
    }

    if(Url.size() > 0)
    {
        qDebug() << "文件路径：" << Url;
    }
    else
    {
        qDebug() << "文件路径：无";
    }

}

//MusicFileInfo::MusicFileInfo()
//{

//}

MusicFileInfo* MP3File::GetAllInfo(const wchar_t *url, int songNumber)
{
    m_url = QString::fromWCharArray(url);
    MusicFileInfo* music_info = new MusicFileInfo;

    bool hasID3v2 = false;

    int start = 0;
    int left = 0;
    int right = 0;

    while(url[right] != L'\0')
    {
        if(url[right] == L'/')
            left = right + 1;
        right++;
    }

    int end = right;

    while(url[right] != L'.' && right != left)
    {
        right--;
    }

    if(right == left)
    {
        right = end;
    }

    music_info->File_name = QString::fromWCharArray(url + left, right - left);

    qDebug() << music_info->File_name;

    //路径可能含有中文，所以用_wfopen,fopen只能用ASCII
    FILE* fp = _wfopen(url, L"rb");

    if (NULL == fp)
    {
         printf("open read file error!!");
         music_info->pic_flag = false;
         return music_info;
    }

    music_info->Url = m_url;

    fseek(fp,0,SEEK_SET);
    // 读取帧头
    fread(&Header,1,3,fp);

    // 这里的ID3V2以及帧标识的大小由标准规定均为10个字节
    // 读取帧头，这里就是为了判断是否是ID3V2的标签头
    if ((Header[0] == 'I' || Header[0] == 'i') &&
        (Header[1] == 'D' || Header[1] == 'd') &&
         Header[2] == '3')
    {
        hasID3v2 = true;
        qDebug()<<"ID3v2 exit!";
    }
    else
    {
        printf("No ID3V2!");
        music_info->pic_flag = false;
    }

    if(hasID3v2)
    {
        //读取ID3V2帧大小
        fseek(fp,6,SEEK_SET);
        fread(&Header_size,1,4,fp);
        mp3_TagSize = (Header_size[0] & 0x7f) << 21
                    | (Header_size[1] & 0x7f) << 14
                    | (Header_size[2] & 0x7f) << 7
                    | (Header_size[3] & 0x7f);

        // 开始解析标签帧
        unsigned int cur = 0;

        //获取图片
        while(cur < mp3_TagSize)
        {
            Frame m_frame;
            fread(&m_frame, 10, 1, fp);

            //计算帧的大小
            framecount = (int)(m_frame.Size[0] << 24
                    | m_frame.Size[1] << 16
                    | m_frame.Size[2] << 8
                    | m_frame.Size[3]);

            cur += 10;

            //ID3V2帧后面部分全为空，不含有任何内容，判断FrameID是否为空即可，为空则停止解析
            if((strncmp(m_frame.FrameID, "\x0000", 4)) == 0)
            {
                break;
            }

            qDebug() << m_frame.FrameID << framecount << ';';

            //标题
            if((strncmp(m_frame.FrameID, "TIT2", 4)) == 0)
            {
                char ID3_title[framecount];
                fread(ID3_title, framecount, 1, fp);

                QByteArray tmp;
                CodeInfo code_info = getCodeInfo(ID3_title); //获取编码信息

    //            qDebug() << code_info.char_set << code_info.endian << code_info.offset;

                if(code_info.endian != IsBigEndian()) //判断字符大小端是否与操作系统的大小端一致
                {
                    big2little((wchar_t *)ID3_title + code_info.offset, (framecount - code_info.offset)/2);
                }

                for(int i = code_info.offset; i < framecount; i++)
                {
                        tmp += ID3_title[i];
                }

                QTextCodec *codec = QTextCodec::codecForName(code_info.char_set);
                QString ua = codec->toUnicode(tmp);
    //            qDebug() << ua;

                music_info->Name = ua;
            }
            //歌手
            else if((strncmp(m_frame.FrameID, "TPE1", 4)) == 0)
            {
                char ID3_singer[framecount];
                fread(ID3_singer, framecount, 1, fp);

                QByteArray tmp;
                CodeInfo code_info = getCodeInfo(ID3_singer); //获取编码信息

    //            qDebug() << code_info.char_set << code_info.endian << code_info.offset;

                if(code_info.endian != IsBigEndian()) //判断字符大小端是否与操作系统的大小端一致
                {
                    big2little((wchar_t *)ID3_singer + code_info.offset, (framecount - code_info.offset)/2);
                }

                for(int i = code_info.offset; i < framecount; i++)
                {
    //                    tmp += ID3_singer[i]; //QString一个单位是2个字节，所以一个ID3_singer[i]大小为1个字节，放入QString之后变成2个字节，所以后面转换的时候会失败
                        tmp += ID3_singer[i];
                }

                QTextCodec *codec = QTextCodec::codecForName(code_info.char_set);
                QString ua = codec->toUnicode(tmp);
    //            qDebug() << ua;

                music_info->Singer = ua;
            }
            //专辑
            else if((strncmp(m_frame.FrameID, "TALB", 4)) == 0)
            {
                char ID3_time[framecount];
                fread(ID3_time, framecount, 1, fp);

                QByteArray tmp;

                CodeInfo code_info = getCodeInfo(ID3_time);

    //            qDebug() << code_info.char_set << code_info.endian << code_info.offset;

                if(code_info.endian != IsBigEndian())
                {
                    big2little((wchar_t *)ID3_time + code_info.offset, (framecount - code_info.offset)/2);
                }

                for(int i = code_info.offset; i < framecount; i++)
                {
                        tmp += ID3_time[i];
                }

                QTextCodec *codec = QTextCodec::codecForName(code_info.char_set);
                QString ua = codec->toUnicode(tmp);

                music_info->Album = ua;
            }
            //其他略过
            else
            {
                // 移动到下一帧标识
                fseek(fp, framecount, SEEK_CUR);
            }

            cur += framecount;
        }
    }

    music_info->Time = getTime(fp, hasID3v2? mp3_TagSize + 10 : 0);

    //解析ID3V1
//    ID3V1Frame id3v1_frame;
//    fseek(fp, -128 * (long)sizeof(char), SEEK_END);
//    fread(&id3v1_frame, 128, 1, fp);

//    music_info.Name = id3v1_frame.Title;
//    music_info.Album = id3v1_frame.Album;
//    music_info.Singer = id3v1_frame.Artist;

    fclose(fp);
    return music_info;
}

int MP3File::getBitrate(int version_id, int layer_index, int bit_index)
{
    if(version_id ==  3)
    {
        return bitrate_table[3 - layer_index][bit_index];
    }
    else if(version_id == 2 || version_id == 0)
    {
        return bitrate_table[6 - layer_index][bit_index];
    }
    else
        return -1;
}

int MP3File::getSideInfoSize(int version_id, int layer_index, int channel_index)
{
    if(layer_index != 1)
    {
        return 0;
    }

    if(version_id == 3)
    {
        if(channel_index == 3)
        {
            return 17;
        }
        else
            return 32;
    }
    else
    {
        if(channel_index == 3)
        {
            return 9;
        }
        else
            return 17;
    }
}

int MP3File::getTime(FILE* fp, int ID3V2_len)
{
    fseek(fp, 0L, SEEK_END); //移文件指针到文件尾
        int file_length = ftell(fp);   //文件长

        //MPEG帧头的大小为4个字节
        unsigned char MPEG_head[4] = {0};

        //到帧头的字节偏移
        int cur = ID3V2_len;

        std::cout << "first cur: " << cur << std::endl;
        // fseek(fp, cur, SEEK_SET);
        // std::cout << "fp pos: " << ftell(fp) << std::endl;

        int i = 0;

        //MPEG 版本: 0-MPEG 2.5; 1 - reserve; 2 - MPEG 2; 3 - MPEG 1
        unsigned short version_id; // (MPEG_head[1] & 0x18) >> 3;

        //Layer: 0 - reserve; i - layer (4 - i);
        unsigned short layer_index; // (MPEG_head[1] & 0x06) >> 1

        // 1 为无CRC，0 为包含16位的CRC校验
        unsigned short protection; // (MPEG_head[1] & 0x01)

        // 比特率索引
        unsigned short bit_index;  // (MPEG_head[2] & 0xF0) >> 4

        //采样率索引: 11-reserve
        unsigned short sample_index; // (MPEG_head[2] & 0x0C) >> 2;

        //填充位
        unsigned short padding; // (MPEG_head[2] & 0x02) >> 1;

        //声道的模式
        unsigned short channel_index; //(MPEG_head[3] & 0xC0) >> 6;


        //先找到第一帧
        while(cur + 4 < file_length)
        {
            fseek(fp, cur, SEEK_SET);
            fread(MPEG_head, 1, 4, fp);

            layer_index = (MPEG_head[1] & 0x06) >> 1;
            bit_index = MPEG_head[2] / 0x10; //   比特率索引 != '1111'
            sample_index = (MPEG_head[2] & 0x0C) >> 2;

            if(MPEG_head[0] == 0xFF
                && MPEG_head[1] > 0xE0
                && bit_index != 0xF
                && layer_index != 0x0
                && sample_index < 0x3)
            {
                if(bit_index == 0)
                {
                    printf("This a Free Rate MP3 File!\n");
                    return 0;
                }
                break;
            }
            i += 1;
            cur += 1;
        }

        // 显示MPEG帧头的编码
//        for(int i = 7; i >= 0; i--)
//        {
//            char c = (MPEG_head[0] >> i) & 0x01;
//            c = c + '0';
//            std::cout << char(c) << ' ';
//        }

//        for(int i = 7; i >= 0; i--)
//        {
//            char c = (MPEG_head[1] >> i) & 0x01;
//            c = c + '0';
//            std::cout << char(c) << ' ';
//        }

//        std::cout <<std::endl;

//        for(int i = 7; i >= 0; i--)
//        {
//            char c = (MPEG_head[2] >> i) & 0x01;
//            c = c + '0';
//            std::cout << char(c) << ' ';
//        }

//        for(int i = 7; i >= 0; i--)
//        {
//            char c = (MPEG_head[3] >> i) & 0x01;
//            c = c + '0';
//            std::cout << char(c) << ' ';
//        }

//        std::cout <<std::endl;
//        std::cout << "-------------------" <<std::endl;

        if(cur == file_length)
        {
            qDebug() << "未找到第一个MPEG帧";
            fclose(fp);
            return 0;
        }

        //std::cout << "偏移" << i << "字节找到第一个MPEG帧" << std::endl;
        qDebug() << QString("偏移%1字节找到第一个MPEG帧").arg(i);

        version_id = (MPEG_head[1] & 0x18) >> 3;
        protection = (MPEG_head[1] & 0x01);
        padding = (MPEG_head[2] & 0x02) >> 1;
        channel_index = (MPEG_head[3] & 0xC0) >> 6;

        int padding_size = layer_index == 3? 4 * padding : 1 * padding;

        //帧大小
        unsigned frame_size = 0;
        //比特率
        unsigned short biterate = getBitrate(version_id, layer_index, bit_index);
        //MP3播放时间
        int mp3_duration = 0;
        //帧数
        int frame_cnt = 0;

        //std::cout << "比特率: "<< biterate << "Kbs" << std::endl;

        //比特率索引不为0
        if(bit_index != 0)
        {
            //每帧的播放时间: 每帧的采样数/每帧的采样频率 单位：ms
            float time_per_flame = float(sampling_per_flame_table[version_id][3-layer_index]) * 1000 / samplingrate_table[version_id][sample_index];
            //std::cout << "每帧持续时间: "<< time_per_flame << "s" << std::endl;
            qDebug() << QString("每帧持续时间: %1 ms").arg(time_per_flame);

            switch(version_id)
            {
                case 0:
                    qDebug() << QString("MPEG 2.5, layer %1, %2Hz, %3\n").arg(4-layer_index).arg(samplingrate_table[version_id][sample_index]).arg(channel[channel_index]);
                    //计算帧大小 （（每帧的采样数 / 8 * 比特率）/ 采样率）+ padding
                    frame_size = ((72000 * biterate) / samplingrate_table[version_id][sample_index]) + padding_size;
                    //计算帧数
                    frame_cnt = (int)((file_length - ftell(fp) + 10)/frame_size);

                    mp3_duration = frame_cnt * time_per_flame;

                    printf("MPEG 2.5, layer %d, %dHz  %s\n",4-layer_index,
                                        samplingrate_table[version_id][sample_index],
                                        &(channel[channel_index]));

                    printf("CBR:-> %dKbit/s %dframe\n", biterate, frame_cnt);
                    printf("Time Duration: %d second", mp3_duration);
                    break;

                case 2:
                    qDebug() << QString("MPEG 2, layer %1, %2Hz, %3\n").arg(4-layer_index).arg(samplingrate_table[version_id][sample_index]).arg(channel[channel_index]);
//                    printf("MPEG 2, layer %d, %dHz  %s\n",4-layer_index,
//                                        samplingrate_table[version_id][sample_index],
//                                        channel[channel_index]);

                    frame_size = ((72000 * biterate) / samplingrate_table[version_id][sample_index]) + padding_size;
                    frame_cnt = (int)((file_length - ftell(fp) + 10)/frame_size);

                    mp3_duration = frame_cnt * time_per_flame;
                    printf("CBR:-> %dKbit %dframe\n", biterate, frame_cnt);
                    printf("Length: %d second", mp3_duration);
                    break;

                case 3:
                    qDebug() << QString("MPEG 1, layer %1, %2Hz, %3\n").arg(4-layer_index).arg(samplingrate_table[version_id][sample_index]).arg(channel[channel_index]);
//                    printf("MPEG 1, layer %d, %dHz  %s\n",4-layer_index,
//                                        samplingrate_table[version_id][sample_index],
//                                        channel[channel_index]);

                    frame_size = ((144000 * biterate) / samplingrate_table[version_id][sample_index]) + padding_size;
                    frame_cnt = (int)((file_length - ftell(fp) + 10)/frame_size);

                    mp3_duration = frame_cnt * time_per_flame;
//                    printf("CBR:-> %dKbit %dframe\n", biterate, frame_cnt);
//                    printf("Length: %d second", mp3_duration);
                    qDebug() << QString("CBR:-> %1Kbit %2 frame\nTime: %3 ms").arg(biterate).arg(frame_cnt).arg(mp3_duration);
                    break;

                default:
                    break;
            }
        }
        else
        {
            printf("\nThis a Free Rate MP3 File!\n");
        }

        //判断是否为VBR格式，此处仅判断XING，暂不判断VBRI,不判断AVR

        //先计算XING头位置， MPEG头位置 + 4 + CRC校检大小 + 边信息大小，目前指针在MPEG头位置 + 4的位置
        // 如果有CRC校检，偏移16bit
        if(protection == 0)
        {
            fseek(fp, 2, SEEK_CUR);
        }

        //边信息大小
        int side_info_size = getSideInfoSize(version_id, layer_index, channel_index);
        if(side_info_size == 0)
        {
            std::cout << "计算MP3边信息错误。" << std::endl;
            return mp3_duration;
        }

        fseek(fp, side_info_size, SEEK_CUR);

        unsigned char XING_HEAD[4] = {0};

        fread(XING_HEAD, 4, 1, fp);

        if(( XING_HEAD[0] == 'X' || XING_HEAD[0] == 'x') &&
            (XING_HEAD[1] == 'I' || XING_HEAD[1] == 'i') &&
            (XING_HEAD[2] == 'N' || XING_HEAD[2] == 'n') &&
            (XING_HEAD[3] == 'G' || XING_HEAD[3] == 'g'))
        {
            // bool hasFrames = false;
            // fread(XING_HEAD, 4, 1, fp);
            // if(XING_HEAD[3] & 0x01 == 1)
            //     hasFrames = true;

            // if(hasFrames)
            // {
            //     fread(XING_HEAD, 4, 1, fp);
            //     //大端转小端，win10为小端
            //     big2little(XING_HEAD, 4);

            //     long long frames = XING_HEAD[0] * 0x1000000 +
            //             XING_HEAD[1] * 0x10000 +
            //             XING_HEAD[2] * 0x100 +
            //             XING_HEAD[3];

            //     mp3_duration = frames * sampling_per_flame_table[version_id][3-layer_index] /
            //      samplingrate_table[version_id][sample_index];
            // }

            qDebug() << "Xing Header";
        }

        qDebug() << "-------------------";

        fclose(fp);
        return mp3_duration;
}

bool MusicFileInfo::readPic()
{
    pic_flag = false;
    if(Url.size() == 0)
    {
        qDebug() << "empty url";
        return false;
    }

    auto archiveWString = Url.toStdWString();
    wchar_t* url = const_cast<wchar_t *>(archiveWString.c_str());

    if(File_name.size() == 0)
    {
        int start = 0;
        int left = 0;
        int right = 0;

        while(url[right] != L'\0')
        {
            if(url[right] == L'/')
                left = right + 1;
            right++;
        }

        int end = right;

        while(url[right] != L'.' && right != left)
        {
            right--;
        }

        if(right == left)
        {
            right = end;
        }

        File_name = QString::fromWCharArray(url + left, right - left);

        qDebug() << File_name;
    }

    //路径可能含有中文，所以用_wfopen,fopen只能用ASCII
    FILE* fp = _wfopen(url, L"rb");

    if (NULL == fp)
    {
         printf("open file error!!");
         return false;
    }

    unsigned char Header[3];
    unsigned char FrameId[4];     //存放帧标识
    unsigned char Header_size[4];
    unsigned int mp3_TagSize;
    unsigned char frameSize[4];      //存放该帧内容的大小
    unsigned int framecount;          //计算出帧内容的大小

    fseek(fp,0,SEEK_SET);
    // 读取帧头
    fread(&Header,1,3,fp);

    // 这里的ID3V2以及帧标识的大小由标准规定均为10个字节
    // 读取帧头，这里就是为了判断是否是ID3V2的标签头
    if ((Header[0] == 'I' || Header[0] == 'i') &&
        (Header[1] == 'D' || Header[1] == 'd') &&
         Header[2] == '3')
    {
        qDebug()<<"ID3v2 exit!";
    }
    else
    {
        printf("No ID3v2!");
        return false;
    }

    //读取ID3V2帧大小
    fseek(fp,6,SEEK_SET);
    fread(&Header_size,1,4,fp);
    mp3_TagSize = (Header_size[0] & 0x7f) << 21
                | (Header_size[1] & 0x7f) << 14
                | (Header_size[2] & 0x7f) << 7
                | (Header_size[3] & 0x7f);

    // 开始解析标签帧
    unsigned int cur = 0;
    //获取图片
    while(cur < mp3_TagSize)
    {
        Frame m_frame;
        fread(&m_frame, 10, 1, fp);

        //计算帧的大小
        framecount = (int)(m_frame.Size[0] << 24
                | m_frame.Size[1] << 16
                | m_frame.Size[2] << 8
                | m_frame.Size[3]);

        cur += 10;

        //ID3V2帧后面部分全为空，不含有任何内容，判断FrameID是否为空即可，为空则停止解析
        if((strncmp(m_frame.FrameID, "\x0000", 4)) == 0)
        {
            break;
        }

        qDebug() << m_frame.FrameID << framecount << ';';

        //图片
        if((strncmp(m_frame.FrameID, "APIC", 4)) == 0)
        {
            unsigned char* ID3_pic = (unsigned char*)calloc(framecount, 1);
            fread(ID3_pic, framecount, 1, fp);
            int start = 0;
            int pic_type = 0;

            while (start < framecount)
            {
                if ((ID3_pic[start] == 0xFF) &&
                        (ID3_pic[start+1] == 0xD8))
                {
                    pic_type = 1;
                    Picture_type = ".jpg";
                    break;
                }
                else if ((ID3_pic[start] == 0x89) &&
                         (ID3_pic[start+1] == 0x50))
                {
                    pic_type = 2;
                    Picture_type = ".png";
                    break;
                }

                ++start;
            }

            if(pic_type > 0)
            {
                 // 这里没有错误处理，从简
                 QString pic_url = "Album/" + File_name + Picture_type;
                 qDebug() << pic_url;
                 QFile file(pic_url);
                 if (!file.open(QIODevice::WriteOnly))
                 {
                     qDebug("打开文件失败！");
                     continue;
                 }

                 file.write((char*)ID3_pic + start, framecount - start);
                 file.close();

                 pic_flag = true;
                 Picture_url = pic_url;

            }
            else
            {
                qDebug() << "无法解析封面格式";
            }
            break;
        }
        //其他略过
        else
        {
            // 移动到下一帧标识
            fseek(fp, framecount, SEEK_CUR);
        }

        cur += framecount;
    }

    fclose(fp);
    return true;
}
